/*
 * Microchip MRF49XA device driver
 *
 *    Author : Vincent Del Medico <vincent dot del dot medico at gmail dot com>
 *
 * Based on Microchip MRF49XA controller driver written by
 * William Dillon, Copyright 2010 Oregon State University. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 *
 *
 *  !!!!!!!!!!!!!!!!!!!!!!!!! BE WARNED !!!!!!!!!!!!!!!!!!!!!!!!!!!!
 * THIS DRIVER MIGHT VIOLATE THE LAWS OF YOUR COUNTRY
 * EACH COUNTRY HAS ITS OWN RULES REGARDING RADIOFREQUENCY EMISSIONS
 * THIS DRIVER IS PROVIDED AS IS, AND IS NOT BUG-FREE
 * USE AT YOUR OWN RISKS
 *
 *
 *
 *
 *   Your platform definition file should specify something like:
 *
 * static struct spi_board_info __initdata mini2440_spi_board_info[] = {
 * {
 *   .modalias      = "mrf49xa",
 *   .max_speed_hz   = 2400000,
 *   .bus_num      = 0,
 *   .chip_select   = 0,   
 *   .mode          = SPI_MODE_0,
 *   .irq = IRQ_EINT18,
 * },
 * };
 *
 * static void mini2440_spi0_cs(struct s3c2410_spi_info *spi, int cs, int pol)
 * {
 *     s3c2410_gpio_setpin(S3C2410_GPG(2), pol);
 * }
 *
 * static struct s3c2410_spi_info mini2440_spi0_platdata = {
 *    .num_cs = 1,
 *    .bus_num = 0,
 *    .set_cs = mini2440_spi0_cs,
 * };
 *
 * Also configure your GPIOs inside machine init function, like :
 * s3c2410_gpio_cfgpin(S3C2410_GPE(11), S3C2410_GPE11_SPIMISO0);
 * s3c2410_gpio_cfgpin(S3C2410_GPE(12), S3C2410_GPE12_SPIMOSI0);
 * s3c2410_gpio_cfgpin(S3C2410_GPE(13), S3C2410_GPE13_SPICLK0);
 * s3c2410_gpio_cfgpin(S3C2410_GPG(2), S3C2410_GPIO_OUTPUT);
 * s3c2410_gpio_cfgpin(S3C2410_GPG(10), S3C2410_GPIO_INPUT); // IRQ i/o
 * s3c_device_spi0.dev.platform_data = &mini2440_spi0_platdata;
 * spi_register_board_info(mini2440_spi_board_info,
 * ARRAY_SIZE(mini2440_spi_board_info));
 * printk(KERN_ERR "Setup SPI0\n");
 *
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/compat.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/spi/spi.h>

#include <plat/gpio-cfg.h>
#include <plat/regs-spi.h>
#include <mach/regs-gpio.h>
#include <mach/spi.h>
#include <asm/gpio.h>
#include <asm/uaccess.h>


#include "mrf49xa.h"


#define MRF49XA_MAJOR 253

struct mrf49xa_data {
    dev_t             devt;
    struct spi_device   *spi;
    unsigned           users;
    mrf_state          state;
    mrf_packet         mrf_packets;
    uint8_t            transmit_buffer[sizeof(mrf_packet)+8];
    uint8_t            nbr_of_rx_packets;
    uint8_t            TxCounter;
    uint8_t            RxCounter;
    void __iomem        *regs;
};

static void MRF_ModeTransmit(struct mrf49xa_data *mrf49xa);

static struct mrf49xa_data *probed_mrf49xa;
static uint16_t L_gencreg = MRF_GENCREG;

/* Module parameters */
static unsigned int rf_frequency = 434000000;
module_param(rf_frequency, uint, S_IRUGO);
MODULE_PARM_DESC(rf_frequency, "Center frequency of RF communication, in Hz");

static unsigned int rf_rxbw = 400000;
module_param(rf_rxbw, uint, S_IRUGO);
MODULE_PARM_DESC(rf_rxbw, "RF receiver bandwidth, in Hz");

static unsigned int rf_mod_bw = 120000;
module_param(rf_mod_bw, uint, S_IRUGO);
MODULE_PARM_DESC(rf_mod_bw, "RF FSK modulation bandwidth, in Hz");

static unsigned int baud_rate = 1200;
module_param(baud_rate, uint, S_IRUGO);
MODULE_PARM_DESC(baud_rate, "Baud rate, in bps");

static unsigned int load_cap = 10;
module_param(load_cap, uint, S_IRUGO);
MODULE_PARM_DESC(load_cap, "Load capacitance of Xtal, in pF");

/* COMPILATION WARNING */
#warning "*  !!!!!!!!!!!!!!!!!!!!!!!!! BE WARNED !!!!!!!!!!!!!!!!!!!!!!!!!!!!"
#warning " * THIS DRIVER MIGHT VIOLATE THE LAWS OF YOUR COUNTRY"
#warning " * EACH COUNTRY HAS ITS OWN RULES REGARDING RADIOFREQUENCY EMISSIONS"
#warning " * THIS DRIVER IS PROVIDED AS IS, AND IS NOT BUG-FREE"
#warning " * USE AT YOUR OWN RISKS"

#ifdef MRF49XA_DIRTY_SPI
#warning "DIRTY SPI"
/* This function is a highly dirty SPI wrapper for low latency SPI read/write ops
As Linux SPI interface uses queues and (at least) 1 processus, and because the MRF49XA
device only has a 1-byte buffer, we need to implement a fast version of SPI r/w operations
for high RF data rates.
Another option is to improve Linux SPI driver but that's not the point of this driver.

Note : this function has especially be written for S3C24xx board 

*/
static uint16_t SPI_w16r16(uint16_t P_cmd, struct mrf49xa_data *mrf49xa)
{
    uint16_t L_retval = 0;

    /* CS LOW */
    gpio_set_value(S3C2410_GPG(2), 0);
    writeb(S3C2410_SPCON_MSTR | S3C2410_SPCON_ENSCK, mrf49xa->regs + S3C2410_SPCON);
    
    /* Write byte */
    writeb(P_cmd>>8, mrf49xa->regs + S3C2410_SPTDAT);

    /* Wait for end of transmit */
    while ( (readb(mrf49xa->regs + S3C2410_SPSTA) & 1) == 0);
    
    /* Read byte */
    L_retval = readb(mrf49xa->regs + S3C2410_SPRDAT);
    L_retval <<= 8;

    /* Write byte */
    writeb( (uint8_t)(P_cmd & 0x00FF), mrf49xa->regs + S3C2410_SPTDAT);

    /* Wait for end of transmit */
    while ( (readb(mrf49xa->regs + S3C2410_SPSTA) & 1) == 0);
    
    /* Read byte */
    L_retval |= (uint16_t)readb(mrf49xa->regs + S3C2410_SPRDAT);

    /* CS HIGH */
    writeb(S3C2410_SPCON_MSTR, mrf49xa->regs + S3C2410_SPCON);
    gpio_set_value(S3C2410_GPG(2), 1);

    return L_retval;
}
#endif

static ssize_t mrf49xa_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
    struct mrf49xa_data    *mrf49xa;
    ssize_t           status = 0;
    mrf_packet *packet;
    
    /* Get the device structure */
    mrf49xa = filp->private_data;

    if (mrf49xa->nbr_of_rx_packets)
    {
        /* Copy content of received packet, if the user gave enough memory */
        packet = &mrf49xa->mrf_packets;
        if (count >= packet->length)
        {
           copy_to_user(buf, (uint8_t*)packet, packet->length);
           status = packet->length;
           mrf49xa->nbr_of_rx_packets--;
        }
        else
        {
           status = -EMSGSIZE;
        }
    }

    /* TODO : handle multiple RX buffers */
    return status;
}

static ssize_t mrf49xa_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
    int retval = -1;
    struct mrf49xa_data    *mrf49xa;

    /* Get the device structure */
    mrf49xa = filp->private_data;

    if (mrf49xa != NULL)
    {
        /* Get content of packet */
        copy_from_user( (uint8_t*)mrf49xa->transmit_buffer+4, buf, count);

        /* Start transmission */
        MRF_ModeTransmit(mrf49xa);
        retval = count;
    }

    return retval;
}

static long mrf49xa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    long retval = 0;

    /* TODO */

    return retval;
}

#ifdef CONFIG_COMPAT
static long
mrf49xa_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    return mrf49xa_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
}
#else
#define mrf49xa_compat_ioctl NULL
#endif /* CONFIG_COMPAT */


static uint16_t MRF_SetRegister(uint16_t P_setting, struct mrf49xa_data *mrf49xa)
{
    uint16_t L_retval = 0;

#ifdef MRF49XA_DIRTY_SPI
    L_retval = SPI_w16r16(P_setting, mrf49xa);
#else
    uint8_t L_buffer[2];
    struct spi_message    m;
    struct spi_transfer t = {
        .tx_buf = L_buffer,
        .rx_buf = L_buffer,
        .len = 2,
        .bits_per_word = mrf49xa->spi->bits_per_word,
        .speed_hz = mrf49xa->spi->max_speed_hz,
        .delay_usecs = 1,
    };

    L_buffer[0] = P_setting>>8;
    L_buffer[1] = P_setting & 0x00FF;

    spi_message_init(&m);
    spi_message_add_tail(&t, &m);
    spi_sync(mrf49xa->spi, &m);
    L_retval = (((uint16_t)L_buffer[0])<<8) | L_buffer[1];
#endif
    return L_retval;
}

static uint8_t MRF_ReadFIFO(struct mrf49xa_data *mrf49xa)
{
    uint16_t L_data;

    L_data = MRF_SetRegister(MRF_RXFIFOREG, mrf49xa);

    return (uint8_t)(L_data & 0x00FF);
}

static void MRF_Reset(struct mrf49xa_data *mrf49xa)
{
    MRF_SetRegister(MRF_PMCREG, mrf49xa);
    MRF_SetRegister(MRF_FIFORSTREG | MRF_DRSTM | ((8 << 4) & MRF_FFBC_MASK), mrf49xa);
    MRF_SetRegister(L_gencreg, mrf49xa);
    MRF_SetRegister(L_gencreg | MRF_FIFOEN, mrf49xa);
    MRF_SetRegister(MRF_FIFORSTREG | MRF_DRSTM | ((8 << 4) & MRF_FFBC_MASK) | MRF_FSCF, mrf49xa);
    MRF_SetRegister(MRF_PMCREG | MRF_RXCEN, mrf49xa);
}

static void MRF_Init(struct mrf49xa_data *mrf49xa)
{
    int L_drpe = 0;
    uint32_t L_modbw = 0;
    uint16_t L_rxbw = 0;
    uint32_t L_drpv = 0;
    uint32_t L_drpv0 = 0;
    uint32_t L_drpv1 = 0;
    uint32_t L_freqb = 0;
    uint16_t L_drsreg = MRF_DRSREG;
    uint8_t L_loadCapacitance = load_cap;
    uint32_t L_fa0, L_fa1;

    L_gencreg = MRF_GENCREG;
    
    /* Configure Load capacitange */
    if (load_cap == 0 || load_cap > 15)
    {
         dev_err(&mrf49xa->spi->dev, "Warning : load capacitance forced to 10pF.");
         L_loadCapacitance = 10;
    }
    L_gencreg |= L_loadCapacitance;

    /* Configure RF frequency band */
    if (rf_frequency > 430240000 && rf_frequency < 439757500)
    {
        L_gencreg |= MRF_FBS_434;
        L_fa0 = 43;
        L_fa1 = 1;
    }
    else if (rf_frequency > 860480000 && rf_frequency < 879515000)
    {
         L_gencreg |= MRF_FBS_868;
         L_fa0 = 43;
         L_fa1 = 2;
    }
    else if (rf_frequency > 900720000 && rf_frequency < 929272500)
    {
         L_gencreg |= MRF_FBS_915;
         L_fa0 = 30;
         L_fa1 = 3;
    }
    else
    {
        dev_err(&mrf49xa->spi->dev, "Unsupported RF frequency (%d).\r\nForced to 434MHz", rf_frequency);
        L_gencreg |= MRF_FBS_434;
        rf_frequency = 434000000;
        L_fa0 = 43;
        L_fa1 = 1;
    }

    /* Fine-tune RF center frequency
     * L_freqb should be in range of 96 to 3903, according to the datasheet
     * This is guarantied by the above frequency limitations
     */
    L_freqb = 4 * rf_frequency;
    L_freqb /= (1000*10*L_fa1);
    L_freqb -= L_fa0*4000;

    /* Compute baud rate
     * DRPV = 10000/[29 * (1 + DPRE * 7) * DREx] - 1
     */
    L_drpv0 = (10000000 / (29 * baud_rate)) - 1;
    L_drpv1 = (10000000 / (29 * baud_rate * 8)) - 1;
    if ( (abs(baud_rate - (10000000/(29 * (L_drpv1 + 1) * 8))) > abs(baud_rate - (10000000/(29 * (L_drpv0 + 1))))) &&
        (L_drpv0 < 128) )
    {
        L_drpv = L_drpv0;
        L_drpe = 0;
        L_drsreg &= ~MRF_DRPE;
    }
    else
    {
        L_drpv = L_drpv1;
        L_drpe = 1;
        L_drsreg |= MRF_DRPE;
    }
    dev_info(&mrf49xa->spi->dev, "Expected baud rate : %dbps .", 10000000/(29 * (L_drpv + 1) * (1 + L_drpe * 7)));
    L_drsreg |= L_drpv;

    /* Check RX bandwidth parameter */
    switch(rf_rxbw)
    {
        case 67000:
            L_rxbw = MRF_RXBW_67K;
            break;
        case 134000:
            L_rxbw = MRF_RXBW_134K;
            break;
        case 200000:
            L_rxbw = MRF_RXBW_200K;
            break;
        case 270000:
            L_rxbw = MRF_RXBW_270K;
            break;
        case 340000:
            L_rxbw = MRF_RXBW_340K;
            break;
        case 400000:
            L_rxbw = MRF_RXBW_400K;
            break;
        default:
            dev_err(&mrf49xa->spi->dev, "Unsupported RX bandwidth.\r\nRX bandwidth forced to 400kHz.\r\nSupported bandwidth are 67kHz, 134kHz, 200kHz, 270kHz, 340kHz and 400kHz.");
            L_rxbw = MRF_RXBW_400K;
            break;
    }

    /* Check Modulation bandwidth parameter */
    if ( (rf_mod_bw % 15000 == 0) && (rf_mod_bw >= 15000) && (rf_mod_bw <= 240000) )
    {
        L_modbw = (rf_mod_bw / 15000) - 1;
        L_modbw <<= 4;
    }
    else
    {
        dev_err(&mrf49xa->spi->dev, "Unsupported modulation bandwidth.\r\nModulation bandwidth forced to 120kHz.\r\nModulation bandwith must be in range of 15kHz to 240kHz, with 15kHz step.");
    }

    /* Configure FIFO, generate interrupt after 8 bits received */
    MRF_SetRegister(MRF_FIFORSTREG | MRF_DRSTM | ((8 << 4) & MRF_FFBC_MASK), mrf49xa);
    MRF_SetRegister((MRF_FIFORSTREG | MRF_DRSTM | ((8 << 4) & MRF_FFBC_MASK)) | MRF_FSCF, mrf49xa);
    /* Set RF band frequency */
    MRF_SetRegister(L_gencreg, mrf49xa);
    /* Set Automatic Frequency Control */
    MRF_SetRegister(MRF_AFCCREG | MRF_AUTOMS_INDP | MRF_ARFO_unlim | MRF_HAM | MRF_FOREN | MRF_FOFEN, mrf49xa);
    /* Set RF center frequency */
    MRF_SetRegister(MRF_CFSREG | ((uint16_t)L_freqb & MRF_FREQB_MASK) , mrf49xa);
    /* Set baud rate */
    MRF_SetRegister(L_drsreg, mrf49xa);
    /* Shutdown everything */
    MRF_SetRegister(MRF_PMCREG | MRF_CLKODIS, mrf49xa);
    /* Set RX bandwidth and Digital RSSI to 103dB */
    MRF_SetRegister(MRF_RXCREG | MRF_FINTDIO | L_rxbw | MRF_DRSSIT_103db, mrf49xa);
    /* Set FSK modulation bandwidth and output power to 0dB (max) */
    MRF_SetRegister(MRF_TXCREG | L_modbw | MRF_OTXPWR_0, mrf49xa);
    MRF_SetRegister(MRF_BBFCREG | MRF_ACRLC | (4 & MRF_DQTI_MASK), mrf49xa);
 
    /* antenna tuning on startup */
    /* Turn ON the transmitter */
    MRF_SetRegister(MRF_PMCREG | MRF_CLKODIS | MRF_TXCEN, mrf49xa);
    /* Wait for oscillator to stabilize */
    mdelay(5);
    /* End of antenna tuning */
 
    /* Turn off transmitter, turn on receiver */
    MRF_SetRegister(MRF_PMCREG | MRF_CLKODIS | MRF_RXCEN, mrf49xa);
    MRF_SetRegister(L_gencreg | MRF_FIFOEN, mrf49xa);
    MRF_SetRegister(MRF_FIFORSTREG | MRF_DRSTM | ((8 << 4) & MRF_FFBC_MASK), mrf49xa);
    MRF_SetRegister(MRF_FIFORSTREG | MRF_DRSTM | ((8 << 4) & MRF_FFBC_MASK) | MRF_FSCF, mrf49xa);
 
    /* Dummy read of status registers to clear Power on reset flag */
    MRF_SetRegister(MRF_STSREG, mrf49xa);
}

static void MRF_ModeReceive(struct mrf49xa_data *mrf49xa)
{
    mrf49xa->state = MRF_STATE_IDLE;
    MRF_SetRegister(MRF_PMCREG | MRF_CLKODIS | MRF_RXCEN, mrf49xa);
    MRF_SetRegister(L_gencreg | MRF_FIFOEN, mrf49xa);
    MRF_SetRegister(MRF_FIFORSTREG | MRF_DRSTM | ((8 << 4) & MRF_FFBC_MASK) | MRF_FFSC, mrf49xa);
    MRF_SetRegister(MRF_FIFORSTREG | MRF_DRSTM | ((8 << 4) & MRF_FFBC_MASK) | MRF_FFSC | MRF_FSCF, mrf49xa);
}

static void MRF_SendByte(uint8_t P_byte, struct mrf49xa_data *mrf49xa)
{
    MRF_SetRegister(MRF_TXBREG | (((uint16_t)P_byte) & 0x00FF) , mrf49xa);
}

static void MRF_ModeTransmit(struct mrf49xa_data *mrf49xa)
{
    mrf49xa->state = MRF_STATE_TRANSMIT;
    MRF_SetRegister(MRF_PMCREG, mrf49xa);                  // Turn everything off
    MRF_SetRegister( L_gencreg | MRF_TXDEN, mrf49xa);    // Enable TX FIFO
    // Reset value of TX FIFO is 0xAAAA
 
    mrf49xa->transmit_buffer[0] = 0xAA;
    mrf49xa->transmit_buffer[1] = 0xAA;
    mrf49xa->transmit_buffer[2] = 0x2D;
    mrf49xa->transmit_buffer[3] = 0xD4;
    mrf49xa->TxCounter = 0;
    MRF_SetRegister(MRF_PMCREG | MRF_TXCEN, mrf49xa);        // Begin transmitting
}

static irqreturn_t mrf49xa_ist(int irq, void *dev_id)
{
    struct mrf49xa_data *mrf49xa = dev_id;
    uint8_t L_length = 0;

    preempt_disable();

    switch(mrf49xa->state)
    {
        case MRF_STATE_IDLE:
           L_length = MRF_ReadFIFO(mrf49xa);
           if ((L_length <= sizeof(mrf_packet)) && ((L_length & 3) == 0) && (L_length >= 8))
           {
              mrf49xa->state = MRF_STATE_RECEIVE;
              mrf49xa->mrf_packets.length = L_length;
              mrf49xa->RxCounter = 1;
           }
           else
           {
              mrf49xa->RxCounter = 0;
              MRF_Reset(mrf49xa);
           }
           break;
        case MRF_STATE_RECEIVE:
           mrf49xa->mrf_packets.payload[mrf49xa->RxCounter-1] = MRF_ReadFIFO(mrf49xa);
           mrf49xa->RxCounter++;
           if (mrf49xa->RxCounter >= mrf49xa->mrf_packets.length)
           {
              mrf49xa->nbr_of_rx_packets++;
              
              /* Back to RX mode */
              MRF_ModeReceive(mrf49xa);
           }
           break;
        case MRF_STATE_TRANSMIT:
           if (mrf49xa->TxCounter > (mrf49xa->transmit_buffer[4] + 4))
           {
              MRF_ModeReceive(mrf49xa);
              mrf49xa->TxCounter = 0;
           }
           else
           {
              MRF_SendByte(mrf49xa->transmit_buffer[mrf49xa->TxCounter], mrf49xa);
              mrf49xa->TxCounter++;
           }
           break;
        default:
           mrf49xa->state = MRF_STATE_IDLE;
           break;
    }
    preempt_enable();
    return IRQ_HANDLED;
}

static int mrf49xa_open(struct inode *inode, struct file *filp)
{
    struct mrf49xa_data    *mrf49xa = probed_mrf49xa;
    int status = -ENXIO;

    /* Only 1 open at a time */
    if (mrf49xa->users == 0)
    {
        filp->private_data = mrf49xa;
        nonseekable_open(inode, filp);
        
        mrf49xa->users = 1;
        mrf49xa->nbr_of_rx_packets = 0;
        mrf49xa->state = MRF_STATE_IDLE;

        /* Init device */
        MRF_Init(mrf49xa);

        /* Request IRQ */
        status = request_threaded_irq(mrf49xa->spi->irq, NULL, mrf49xa_ist, IRQF_TRIGGER_FALLING, "mrf49xa", mrf49xa);
        if (status)
        {
           dev_err(&mrf49xa->spi->dev, "failed to acquire irq %d\n", mrf49xa->spi->irq);
        }
        else
        {
           MRF_ModeReceive(mrf49xa);
        }
    }
    
    return status;
}

static int mrf49xa_release(struct inode *inode, struct file *filp)
{
    struct mrf49xa_data    *mrf49xa;
    int           status = 0;

    mrf49xa = filp->private_data;
    mrf49xa->users = 0;

    filp->private_data = NULL;

    /* Release IRQ */
    free_irq(mrf49xa->spi->irq, mrf49xa);

    return status;
}

static const struct file_operations mrf49xa_fops =
{
    .owner =    THIS_MODULE,
    .write =    mrf49xa_write,
    .read =        mrf49xa_read,
    .unlocked_ioctl = mrf49xa_ioctl,
    .compat_ioctl = mrf49xa_compat_ioctl,
    .open =        mrf49xa_open,
    .release =    mrf49xa_release,
    .llseek =    no_llseek,
};


static struct class *mrf49xa_class;

static int __devinit mrf49xa_probe(struct spi_device *spi)
{
    struct mrf49xa_data *mrf49xa = NULL;
    int status = -ENOMEM;
    struct device *dev = NULL;
#ifdef MRF49XA_DIRTY_SPI
    struct resource *res = NULL;
#endif

    /* Allocate driver data */
    mrf49xa = kzalloc(sizeof(struct mrf49xa_data), GFP_KERNEL);
    if (!mrf49xa)
    { 
        return -ENOMEM;
    }

    /* Create device for MDEV/UDEV  (/dev/mrf49xa) */
    mrf49xa->devt = MKDEV(MRF49XA_MAJOR, 0);
    dev = device_create(mrf49xa_class, &spi->dev, mrf49xa->devt, mrf49xa, "mrf49xa");
    status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
    
    if (status == 0)
    {
        /* Setup SPI driver 
        SPI mode forced to 0
        Max speed is forced to 2.0MHz max according to MRF49XA datasheet
        bits per word is forced to 8 in order to match the current driver
        */
        spi_set_drvdata(spi, mrf49xa);
        
        /* Setup SPI
        */
        spi->mode = SPI_MODE_0;
        if (spi->max_speed_hz > 2000000)
        {
           spi->max_speed_hz = 2000000;
           dev_info(&spi->dev, "Max clock speed reduced to 2.0MHz\n");
        }
        spi->bits_per_word = 8;
        spi_setup(spi);

        probed_mrf49xa = mrf49xa;
        mrf49xa->spi = kzalloc(sizeof (struct spi_device), GFP_KERNEL);
        if (mrf49xa->spi == NULL)
        {
           return -ENOMEM;
        }
        *(mrf49xa->spi) = *(spi);
        mrf49xa->users = 0;
        mrf49xa->nbr_of_rx_packets = 0;

#ifdef MRF49XA_DIRTY_SPI
        res = request_mem_region(0x59000000, 0x1f, "s3c2410-spi.0");
        if (res == NULL)
        {
           dev_info(&spi->dev, "failed to request region.\n");
        }
        mrf49xa->regs = ioremap(0x59000000, 0x1F);
#endif
        dev_info(&spi->dev, "Probed.\n");
    }
    else
    {
        kfree(mrf49xa);
        dev_info(&spi->dev, "Probe failed.\n");
    }

    return status;
}

static int __devexit mrf49xa_remove(struct spi_device *spi)
{
    struct mrf49xa_data    *mrf49xa = spi_get_drvdata(spi);

    kfree(mrf49xa->spi);

    spi_set_drvdata(spi, NULL);

    device_destroy(mrf49xa_class, mrf49xa->devt);
    if (mrf49xa->users == 0)
    {
        kfree(mrf49xa);
    }

    return 0;
}

static struct spi_driver mrf49xa_spi_driver = {
    .driver = {
        .name = "mrf49xa",
        .owner = THIS_MODULE,
    },
    .probe = mrf49xa_probe,
    .remove =  __devexit_p(mrf49xa_remove),

    /* TODO : suspend and resume methods, for power managements */
};

static int __init mrf49xa_init(void)
{
    int status;

    status = register_chrdev(MRF49XA_MAJOR, mrf49xa_spi_driver.driver.name, &mrf49xa_fops);
    if (status < 0)
    {
        return status;
    }

    mrf49xa_class = class_create(THIS_MODULE, "mrf49xa");
    if (IS_ERR(mrf49xa_class))
    {
        unregister_chrdev(MRF49XA_MAJOR, mrf49xa_spi_driver.driver.name);
        return PTR_ERR(mrf49xa_class);
    }

    status = spi_register_driver(&mrf49xa_spi_driver);
    if (status < 0)
    {
        class_destroy(mrf49xa_class);
        unregister_chrdev(MRF49XA_MAJOR, mrf49xa_spi_driver.driver.name);
    }

    return status;
}
module_init(mrf49xa_init);

static void __exit mrf49xa_exit(void)
{
    spi_unregister_driver(&mrf49xa_spi_driver);
    class_destroy(mrf49xa_class);
    unregister_chrdev(MRF49XA_MAJOR, mrf49xa_spi_driver.driver.name);
}
module_exit(mrf49xa_exit);

MODULE_AUTHOR("Vincent DEL MEDICO, <vincent dot del dot medico at gmail dot com>");
MODULE_DESCRIPTION("Microchip MRF49XA device driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:mrf49xa");

